//
//  AirArray.h
//  AirCpp
//
//  Created by Penghao on 14-1-16.
//  Copyright (c) 2014年 PengHao.

//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef __AirCpp__AirArray__
#define __AirCpp__AirArray__

#include <iostream>
#include <stdarg.h>
#include <cassert>
#include <cstdarg>
#include "../AirObject/AirObject.h"
namespace AirCpp{
    
    /**
     *	作为数组的元素容器，其实就是一个链表
     */
    template <class T>
    class AirArrayElement: public AirObject
    {
    public:
        /**
         *	指向下一个对象的指针
         */
        AirArrayElement *p_next;
    public:
        /**
         *	容器中的对象
         */
        T *t;
        
        /**
         *	初始化容器，遵循retaincont
         *
         *	@param 	_t 	对象元素
         */
        AirArrayElement()
        {
        };
        
        
        /**
         *	初始化容器，遵循retaincont
         *
         *	@param 	_t 	对象元素
         *
         *	@return 0 success
         */
        int init(T *_t)
        {
            
            t = retain(_t);
            p_next = NULL;
            return 0;
        }
        
        ~AirArrayElement(){
            release(t);
        }
    };
    
    /**
     *	不可变数组容器
     */
    template <class T>
    class AirArray : public AirObject{
        
    protected:
        AirArrayElement<T> *objects;
        unsigned long obj_count;
        AirArrayElement<T> *last;
        
    protected:
        /**
         *	通过索引获取某一个对象
         *
         *	@param 	index 	对象的索引
         *
         *	@return	返回对象容器
         */
        AirArrayElement<T> *object_at_index(unsigned long index) const{
            AirArrayElement<T> *object = objects;
            for (int i = 1; i <= index; ++i) {
                object = object->p_next;
            }
            return object;
        }
    public:
        
        AirArray():objects(NULL), obj_count(0){
            
        }
        
        
        /**
         *	获取最后一个对象
         *
         *	@return	返回对象容器
         */
        AirArrayElement<T> * last_object(){
            return last;
        }
        
        /**
         *	装载对象到容器
         *
         *	@param 	obj0 	对象指针
         *	@param 	... 	其他对象，以NULL指针结尾
         */
        void init(T *obj0 ,...){
            
            if (obj0==NULL) {
                obj_count = 0;
                return;
            }
            objects = new AirArrayElement<T>(obj0);
            AirArrayElement<T> *p_tmp = objects;
            
            va_list list;
            T *obj;
            va_start(list, obj0);
            obj_count = 0;
            do {
                obj = va_arg(list, T *);
                p_tmp->p_next = new AirArrayElement<T>(obj);
                p_tmp = p_tmp->p_next;
                last = p_tmp;
                ++obj_count;
            } while (obj);
            va_end(list);
        }
        
        /**
         *	重载获取该索引的对象
         *
         *	@param 	index 	索引
         *
         *	@return	对象指针
         */
        T * operator[](unsigned long index) const{
            
            AirArrayElement<T> *object = object_at_index(index);
            if (object != NULL) {
                return object->t;
            }else{
                return NULL;
            }
        }
        
        /**
         *	获取某一对象的索引
         *
         *	@param 	t       该对象指针
         *
         *	@return	如果找到，返回相应索引，如果没有找到，返回-1
         */
        long index_of_object(T *t){
            
            AirArrayElement<T> *object = objects;
            AirArrayElement<T> *p_tmp;
            for (int i = 0; i < obj_count&& object != NULL ; ++i) {
                p_tmp = object;
                if (p_tmp->t == t) {
                    return i;
                }
                object = object->p_next;
            }
            return -1;
        }
        
        /**
         *	获取对向数目
         *
         *	@return	返回容器中对象的数目
         */
        const unsigned long& count() const{
            
            return obj_count;
        }
        
        virtual ~AirArray(){
            AirArrayElement<T> *object = objects;
            AirArrayElement<T> *p_tmp;
            for (int i = 0; i < obj_count; ++i) {
                p_tmp = object;
                object = object->p_next;
                release(p_tmp);
            }
        }
    };
    
    /**
     *	可变数组容器
     */
    template <class T>
    class AirMutableArray : public AirArray<T>{
    public:
        
        /**
         *	移除某个索引的对象
         *
         *	@param 	index 	该索引
         */
        void remove_object_at_index(unsigned long index){
            AirArrayElement<T> *rm_object = AirArray<T>::object_at_index(index);
            AirArray<T>::obj_count-=1;
            if (index == 0) {
                AirArray<T>::objects = rm_object->p_next;
                if ( this->last == rm_object) {
                    this->last = NULL;
                }
                release(rm_object);
            }else{
                AirArrayElement<T> *bf_object = AirArray<T>::object_at_index(index-1);
                bf_object->p_next = rm_object->p_next;
                if ( this->last == rm_object) {
                    this->last = bf_object;
                }
                release(rm_object);
            }
        };
        
        /**
         *	移除某个对象
         *
         *	@param 	object      该对象
         */
        void remove_object(T *object){
            
            long index = AirArray<T>::index_of_object(object);
            remove_object_at_index(index);
        }
        
        void remove_all_object(){
            for (int i = 0; i < AirArray<T>::obj_count; ++i) {
                remove_object_at_index(i);
            }
        }
        
        /**
         *	添加对象
         *
         *	@param 	obj 	添加的对象
         */
        void add_object(T *obj){
            
            AirArrayElement<T> *new_object = new AirArrayElement<T>();
            new_object->init(obj);
            if (AirArray<T>::obj_count == 0) {
                AirArray<T>::objects = new_object;
                
            }else{
                AirArrayElement<T> *last_object = AirArray<T>::last_object();
                last_object->p_next = new_object;
            }
            this->last = new_object;
            AirArray<T>::obj_count+=1;
        }
        
        void insert_object(T *obj, unsigned int index){
            assert(this->count()>=index);
            AirArrayElement<T> *new_ele = new AirArrayElement<T>();
            new_ele->init(obj);
            new_ele->p_next = AirArray<T>::object_at_index(index);
            if (index == 0) {
                AirArray<T>::objects = new_ele;
            }else{
                AirArray<T>::object_at_index(index-1)->p_next = new_ele;
            }
            AirArray<T>::obj_count+=1;
        }
        
        /**
         *	替换某对象
         *
         *	@param 	new_obj 	新的对象
         *	@param 	old_obj 	被替换的对象
         */
        void replace_object(T *new_obj, T *old_obj){
            long index = AirArray<T>::index_of_object(old_obj);
            assert(index>=0);
            
            if (index == -1) {
                //没有找到
            }
            AirArrayElement<T> *new_ele = new AirArrayElement<T>();
            new_ele->init(new_obj);
            new_ele->p_next = AirArray<T>::object_at_index(index+1);
            if (index != 0) {
                // not head
                AirArray<T>::object_at_index(index-1)->p_next = new_ele;
            }else{
                //head
                AirArray<T>::objects = new_ele;
            }
        }
        
        /**
         *	替换某对象到相应的索引中
         *
         *	@param 	new_obj 	新的对象
         *	@param 	index       索引
         */
        void replace_object(T *new_obj, unsigned long index){
            
            T *old_obj = AirArray<T>::object_at_index(index);
            replace_object(new_obj, old_obj);
        }
        
        using AirArray<T>::operator [];
    };
}
#endif /* defined(__AirCpp__AirArray__) */
